package executor

import (
    "context"
    "errors"
    "fmt"
    "strings"
    "testing"
    "time"
    "sync"

    "kwdb-import/pkg/parser"
)

// MockDB 模拟数据库连接
type MockDB struct {
    connected    bool
    transactions int
    executedSQL  []string
    shouldError  bool
    errorMsg     string
    mu           sync.Mutex
}

func (m *MockDB) Connect(ctx context.Context) error {
	if m.shouldError {
		return errors.New(m.errorMsg)
	}
	m.connected = true
	return nil
}

func (m *MockDB) Close() error {
	m.connected = false
	return nil
}

func (m *MockDB) BeginTransaction(ctx context.Context) error {
	if !m.connected {
		return errors.New("not connected")
	}
	if m.shouldError {
		return errors.New(m.errorMsg)
	}
	m.transactions++
	return nil
}

func (m *MockDB) CommitTransaction(ctx context.Context) error {
	if m.transactions == 0 {
		return errors.New("no active transaction")
	}
	if m.shouldError {
		return errors.New(m.errorMsg)
	}
	m.transactions--
	return nil
}

func (m *MockDB) RollbackTransaction(ctx context.Context) error {
	if m.transactions == 0 {
		return errors.New("no active transaction")
	}
	m.transactions--
	return nil
}

func (m *MockDB) ExecuteStatement(ctx context.Context, sql string, stmtType parser.StatementType) error {
    if !m.connected {
        return errors.New("not connected")
    }
    if m.shouldError {
        return errors.New(m.errorMsg)
    }
    m.mu.Lock()
    m.executedSQL = append(m.executedSQL, sql)
    m.mu.Unlock()
    return nil
}

func (m *MockDB) ExecuteBatch(ctx context.Context, statements []string, stmtTypes []parser.StatementType) error {
    if !m.connected {
        return errors.New("not connected")
    }
    if m.shouldError {
        return errors.New(m.errorMsg)
    }
    m.mu.Lock()
    for _, stmt := range statements {
        m.executedSQL = append(m.executedSQL, stmt)
    }
    m.mu.Unlock()
    return nil
}

func (m *MockDB) GetConnectionInfo() string {
	if m.connected {
		return "mock://connected"
	}
	return "mock://disconnected"
}

func (m *MockDB) Ping(ctx context.Context) error {
	if !m.connected {
		return errors.New("not connected")
	}
	if m.shouldError {
		return errors.New(m.errorMsg)
	}
	return nil
}

// TestStatementExecutorInterface 测试StatementExecutor接口
func TestStatementExecutorInterface(t *testing.T) {
    mockDB := &MockDB{}
    executor := mockDB
	
	ctx := context.Background()
	
	// 测试连接
	err := executor.Connect(ctx)
	if err != nil {
		t.Errorf("Connect failed: %v", err)
	}
	
	// 测试Ping
	err = executor.Ping(ctx)
	if err != nil {
		t.Errorf("Ping failed: %v", err)
	}
	
	// 测试事务
	err = executor.BeginTransaction(ctx)
	if err != nil {
		t.Errorf("BeginTransaction failed: %v", err)
	}
	
	// 测试执行语句
	err = executor.ExecuteStatement(ctx, "CREATE TABLE test (id INT);", parser.CreateTable)
	if err != nil {
		t.Errorf("ExecuteStatement failed: %v", err)
	}
	
	// 测试提交事务
	err = executor.CommitTransaction(ctx)
	if err != nil {
		t.Errorf("CommitTransaction failed: %v", err)
	}
	
	// 测试关闭连接
	err = executor.Close()
	if err != nil {
		t.Errorf("Close failed: %v", err)
	}
}

// TestMockDBBasicOperations 测试MockDB基本操作
func TestMockDBBasicOperations(t *testing.T) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 初始状态
	if mockDB.connected {
		t.Error("MockDB should not be connected initially")
	}
	
	// 测试连接
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Errorf("Connect failed: %v", err)
	}
	if !mockDB.connected {
		t.Error("MockDB should be connected after Connect()")
	}
	
	// 测试连接信息
	connInfo := mockDB.GetConnectionInfo()
	if !strings.Contains(connInfo, "connected") {
		t.Errorf("Connection info should indicate connected state: %s", connInfo)
	}
	
	// 测试关闭
	err = mockDB.Close()
	if err != nil {
		t.Errorf("Close failed: %v", err)
	}
	if mockDB.connected {
		t.Error("MockDB should not be connected after Close()")
	}
}

// TestMockDBTransactionManagement 测试事务管理
func TestMockDBTransactionManagement(t *testing.T) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 连接数据库
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Fatalf("Connect failed: %v", err)
	}
	
	// 初始事务数量
	if mockDB.transactions != 0 {
		t.Error("Initial transaction count should be 0")
	}
	
	// 开始事务
	err = mockDB.BeginTransaction(ctx)
	if err != nil {
		t.Errorf("BeginTransaction failed: %v", err)
	}
	if mockDB.transactions != 1 {
		t.Errorf("Transaction count should be 1, got %d", mockDB.transactions)
	}
	
	// 提交事务
	err = mockDB.CommitTransaction(ctx)
	if err != nil {
		t.Errorf("CommitTransaction failed: %v", err)
	}
	if mockDB.transactions != 0 {
		t.Errorf("Transaction count should be 0 after commit, got %d", mockDB.transactions)
	}
	
	// 测试回滚
	err = mockDB.BeginTransaction(ctx)
	if err != nil {
		t.Errorf("BeginTransaction failed: %v", err)
	}
	
	err = mockDB.RollbackTransaction(ctx)
	if err != nil {
		t.Errorf("RollbackTransaction failed: %v", err)
	}
	if mockDB.transactions != 0 {
		t.Errorf("Transaction count should be 0 after rollback, got %d", mockDB.transactions)
	}
}

// TestMockDBStatementExecution 测试语句执行
func TestMockDBStatementExecution(t *testing.T) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 连接数据库
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Fatalf("Connect failed: %v", err)
	}
	
	// 执行单个语句
	sql1 := "CREATE TABLE users (id INT);"
	err = mockDB.ExecuteStatement(ctx, sql1, parser.CreateTable)
	if err != nil {
		t.Errorf("ExecuteStatement failed: %v", err)
	}
	
	if len(mockDB.executedSQL) != 1 {
		t.Errorf("Expected 1 executed SQL, got %d", len(mockDB.executedSQL))
	}
	if mockDB.executedSQL[0] != sql1 {
		t.Errorf("Expected %q, got %q", sql1, mockDB.executedSQL[0])
	}
	
	// 执行批量语句
	batchSQL := []string{
		"INSERT INTO users (id) VALUES (1);",
		"INSERT INTO users (id) VALUES (2);",
		"INSERT INTO users (id) VALUES (3);",
	}
	batchTypes := []parser.StatementType{
		parser.Insert,
		parser.Insert,
		parser.Insert,
	}
	
	err = mockDB.ExecuteBatch(ctx, batchSQL, batchTypes)
	if err != nil {
		t.Errorf("ExecuteBatch failed: %v", err)
	}
	
	if len(mockDB.executedSQL) != 4 { // 1 + 3
		t.Errorf("Expected 4 executed SQL statements, got %d", len(mockDB.executedSQL))
	}
	
	// 验证批量执行的语句
	for i, expectedSQL := range batchSQL {
		actualSQL := mockDB.executedSQL[i+1] // +1 因为第一个是单独执行的
		if actualSQL != expectedSQL {
			t.Errorf("Batch SQL %d: expected %q, got %q", i, expectedSQL, actualSQL)
		}
	}
}

// TestMockDBErrorHandling 测试错误处理
func TestMockDBErrorHandling(t *testing.T) {
	mockDB := &MockDB{
		shouldError: true,
		errorMsg:    "mock error",
	}
	ctx := context.Background()
	
	// 测试连接错误
	err := mockDB.Connect(ctx)
	if err == nil {
		t.Error("Expected connection error, but got none")
	}
	if !strings.Contains(err.Error(), "mock error") {
		t.Errorf("Expected error message to contain 'mock error', got: %v", err)
	}
	
	// 重置错误状态并连接
	mockDB.shouldError = false
	err = mockDB.Connect(ctx)
	if err != nil {
		t.Fatalf("Connect should succeed after resetting error: %v", err)
	}
	
	// 设置错误状态测试其他操作
	mockDB.shouldError = true
	
	// 测试事务错误
	err = mockDB.BeginTransaction(ctx)
	if err == nil {
		t.Error("Expected transaction error, but got none")
	}
	
	// 测试语句执行错误
	err = mockDB.ExecuteStatement(ctx, "SELECT 1;", parser.Other)
	if err == nil {
		t.Error("Expected statement execution error, but got none")
	}
	
	// 测试Ping错误
	err = mockDB.Ping(ctx)
	if err == nil {
		t.Error("Expected ping error, but got none")
	}
}

// TestMockDBDisconnectedOperations 测试断开连接状态下的操作
func TestMockDBDisconnectedOperations(t *testing.T) {
    mockDB := &MockDB{} // 未连接状态
    ctx := context.Background()
    
    // 测试在未连接状态下的操作
    operations := []struct {
        name string
        opFn func() error
    }{
        {"BeginTransaction", func() error { return mockDB.BeginTransaction(ctx) }},
        {"ExecuteStatement", func() error { return mockDB.ExecuteStatement(ctx, "SELECT 1;", parser.Other) }},
        {"ExecuteBatch", func() error { return mockDB.ExecuteBatch(ctx, []string{"SELECT 1;"}, []parser.StatementType{parser.Other}) }},
        {"Ping", func() error { return mockDB.Ping(ctx) }},
    }
	
    for _, op := range operations {
        t.Run(op.name, func(t *testing.T) {
            err := op.opFn()
            if err == nil {
                t.Errorf("%s should fail when not connected", op.name)
            }
            if !strings.Contains(err.Error(), "not connected") {
                t.Errorf("%s error should mention 'not connected', got: %v", op.name, err)
            }
        })
    }
}

// TestMockDBTransactionErrors 测试事务错误情况
func TestMockDBTransactionErrors(t *testing.T) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 连接数据库
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Fatalf("Connect failed: %v", err)
	}
	
	// 测试在没有活动事务时提交
	err = mockDB.CommitTransaction(ctx)
	if err == nil {
		t.Error("CommitTransaction should fail when no active transaction")
	}
	if !strings.Contains(err.Error(), "no active transaction") {
		t.Errorf("Error should mention 'no active transaction', got: %v", err)
	}
	
	// 测试在没有活动事务时回滚
	err = mockDB.RollbackTransaction(ctx)
	if err == nil {
		t.Error("RollbackTransaction should fail when no active transaction")
	}
	if !strings.Contains(err.Error(), "no active transaction") {
		t.Errorf("Error should mention 'no active transaction', got: %v", err)
	}
}

// TestExecutorWithTimeout 测试带超时的执行器操作
func TestExecutorWithTimeout(t *testing.T) {
	mockDB := &MockDB{}
	
	// 创建带超时的上下文
	ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
	defer cancel()
	
	// 正常操作应该在超时前完成
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Errorf("Connect with timeout failed: %v", err)
	}
	
	err = mockDB.ExecuteStatement(ctx, "SELECT 1;", parser.Other)
	if err != nil {
		t.Errorf("ExecuteStatement with timeout failed: %v", err)
	}
	
	err = mockDB.Close()
	if err != nil {
		t.Errorf("Close failed: %v", err)
	}
}

// TestExecutorConcurrency 测试并发执行
func TestExecutorConcurrency(t *testing.T) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 连接数据库
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Fatalf("Connect failed: %v", err)
	}
	
	// 并发执行多个语句
	const numGoroutines = 10
	errorChan := make(chan error, numGoroutines)
	
	for i := 0; i < numGoroutines; i++ {
		go func(id int) {
			sql := fmt.Sprintf("INSERT INTO test (id) VALUES (%d);", id)
			err := mockDB.ExecuteStatement(ctx, sql, parser.Insert)
			errorChan <- err
		}(i)
	}
	
	// 收集结果
	for i := 0; i < numGoroutines; i++ {
		if err := <-errorChan; err != nil {
			t.Errorf("Concurrent execution failed: %v", err)
		}
	}
	
	// 验证所有语句都被执行
	if len(mockDB.executedSQL) != numGoroutines {
		t.Errorf("Expected %d executed statements, got %d", numGoroutines, len(mockDB.executedSQL))
	}
}

// TestStatementPrioritySorting 测试语句优先级排序
func TestStatementPrioritySorting(t *testing.T) {
	// 这个测试需要访问实际的排序函数
	// 由于sortStatementsByPriority是私有函数，我们通过间接方式测试
	
	statements := []string{
		"INSERT INTO users VALUES (1, 'test');",
		"CREATE DATABASE testdb;",
		"CREATE TABLE users (id INT);",
		"CREATE INDEX idx_id ON users(id);",
		"INSERT INTO users VALUES (2, 'test2');",
	}
	
	stmtTypes := []parser.StatementType{
		parser.Insert,
		parser.CreateDatabase,
		parser.CreateTable,
		parser.CreateIndex,
		parser.Insert,
	}
	
	// 预期的排序顺序（基于executor_pgx.go中的优先级）
	// CreateDatabase(1) -> CreateTable(2) -> CreateIndex(3) -> Insert(4)
	expectedOrder := []int{1, 2, 3, 0, 4} // 索引顺序
	
	// 由于我们无法直接测试私有函数，这里只是验证概念
	// 在实际实现中，可以通过公共接口或者将函数导出来测试
	if len(statements) != len(stmtTypes) {
		t.Error("Statements and types length mismatch")
	}
	
	// 验证我们有不同类型的语句
	typeCount := make(map[parser.StatementType]int)
	for _, stmtType := range stmtTypes {
		typeCount[stmtType]++
	}
	
	if len(typeCount) < 3 {
		t.Error("Should have at least 3 different statement types for meaningful sorting test")
	}
	
	// 验证预期顺序的合理性
	if len(expectedOrder) != len(statements) {
		t.Error("Expected order length should match statements length")
	}
}

// BenchmarkMockDBOperations 性能测试
func BenchmarkMockDBOperations(b *testing.B) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 连接数据库
	err := mockDB.Connect(ctx)
	if err != nil {
		b.Fatalf("Connect failed: %v", err)
	}
	
	b.ResetTimer()
	
	b.Run("ExecuteStatement", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			err := mockDB.ExecuteStatement(ctx, "SELECT 1;", parser.Other)
			if err != nil {
				b.Fatalf("ExecuteStatement failed: %v", err)
			}
		}
	})
	
	b.Run("Transaction", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			err := mockDB.BeginTransaction(ctx)
			if err != nil {
				b.Fatalf("BeginTransaction failed: %v", err)
			}
			err = mockDB.CommitTransaction(ctx)
			if err != nil {
				b.Fatalf("CommitTransaction failed: %v", err)
			}
		}
	})
}

// TestExecutorIntegration 集成测试
func TestExecutorIntegration(t *testing.T) {
	mockDB := &MockDB{}
	ctx := context.Background()
	
	// 模拟完整的导入流程
	err := mockDB.Connect(ctx)
	if err != nil {
		t.Fatalf("Connect failed: %v", err)
	}
	
	// 开始事务
	err = mockDB.BeginTransaction(ctx)
	if err != nil {
		t.Fatalf("BeginTransaction failed: %v", err)
	}
	
	// 执行一系列SQL语句
	sqlStatements := []struct {
		sql      string
		stmtType parser.StatementType
	}{
		{"CREATE DATABASE testdb;", parser.CreateDatabase},
		{"CREATE TABLE users (id SERIAL PRIMARY KEY, name VARCHAR(50));", parser.CreateTable},
		{"CREATE INDEX idx_name ON users(name);", parser.CreateIndex},
		{"INSERT INTO users (name) VALUES ('张三');", parser.Insert},
		{"INSERT INTO users (name) VALUES ('李四');", parser.Insert},
	}
	
	for _, stmt := range sqlStatements {
		err = mockDB.ExecuteStatement(ctx, stmt.sql, stmt.stmtType)
		if err != nil {
			t.Errorf("ExecuteStatement failed for %q: %v", stmt.sql, err)
		}
	}
	
	// 提交事务
	err = mockDB.CommitTransaction(ctx)
	if err != nil {
		t.Fatalf("CommitTransaction failed: %v", err)
	}
	
	// 验证所有语句都被执行
	if len(mockDB.executedSQL) != len(sqlStatements) {
		t.Errorf("Expected %d executed statements, got %d", len(sqlStatements), len(mockDB.executedSQL))
	}
	
	// 验证执行的语句内容
	for i, stmt := range sqlStatements {
		if mockDB.executedSQL[i] != stmt.sql {
			t.Errorf("Statement %d: expected %q, got %q", i, stmt.sql, mockDB.executedSQL[i])
		}
	}
	
	// 关闭连接
	err = mockDB.Close()
	if err != nil {
		t.Fatalf("Close failed: %v", err)
	}
}